package com.lkd.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.lkd.business.MsgHandler;
import com.lkd.common.VMSystem;
import com.lkd.config.ConsulConfig;
import com.lkd.config.TopicConfig;
import com.lkd.contract.OrderCheck;
import com.lkd.contract.VendoutContract;
import com.lkd.contract.VendoutData;
import com.lkd.dao.OrderDao;
import com.lkd.feign.UserService;
import com.lkd.vo.*;
import com.lkd.emq.MqttProducer;
import com.lkd.entity.OrderEntity;
import com.lkd.exception.LogicException;
import com.lkd.feign.VMService;
import com.lkd.service.OrderService;
import com.lkd.utils.DistributedLock;
import com.lkd.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    @Autowired
    private VMService vmService;
    @Autowired
    private UserService userService;
    @Autowired
    MqttProducer mqttProducer;
    @Autowired
    ConsulConfig consulConfig;
    @Autowired
    StringRedisTemplate redisTemplate;


    @Override
    public OrderEntity getByOrderNo(String orderNo) {
        QueryWrapper<OrderEntity> qw = new QueryWrapper<>();
        qw.lambda()
                .eq(OrderEntity::getOrderNo, orderNo);
        return this.getOne(qw);
    }

    @Override
    public OrderEntity creatOrder(PayVO payVO) {
        //获取售货机是否还有库存
        Boolean hasCapacity = vmService.hasCapacity(payVO.getInnerCode(), Long.valueOf(payVO.getSkuId()));
        if (!hasCapacity) {

            log.info("该商品已售罄");
            throw new LogicException("该商品已售罄");
        }
        //TODO:分布式锁 机器同一时间只能处理一次出货 传入对应服务的
        DistributedLock lock = new DistributedLock(
                consulConfig.getConsulRegisterHost(),
                consulConfig.getConsulRegisterPort());
        //根据指定的key创建60s时间的有效锁
        DistributedLock.LockContext lockContext = lock.getLock(payVO.getInnerCode() + "_" + payVO.getSkuId(), 60);
        //根据锁的上下文 判断锁是否被使用
        if (!lockContext.isGetLock()) {//TODO:被拦住
            throw new LogicException("机器出货中请稍后重试");
        }
        //存入redis
        redisTemplate.boundValueOps(
                VMSystem.VM_LOCK_KEY_PREF + payVO.getInnerCode() + "_" + payVO.getSkuId())
                .set(lockContext.getSession(),Duration.ofSeconds(60));


        //创建封装类
        OrderEntity order = new OrderEntity();
        order.setOpenId(payVO.getOpenId());
        order.setPayStatus(VMSystem.PAY_STATUS_NOPAY);//支付状态
        order.setStatus(VMSystem.ORDER_STATUS_CREATE);//订单状态
        order.setOrderNo(payVO.getInnerCode() + System.nanoTime());//订单编号
        //封装合作商信息
        VmVO vmInfo = vmService.getVMInfo(payVO.getInnerCode());
        BeanUtils.copyProperties(vmInfo, order);
        order.setAddr(vmInfo.getNodeAddr());//点位地址

        //根据商品编号查询商品信息，并复制给订单对象
        SkuVO sku = vmService.getSku(payVO.getSkuId());
        BeanUtils.copyProperties(sku, order);//给订单设置商品信息
        order.setAmount(sku.getRealPrice());//价格


        //封装合作商
        PartnerVO partner = userService.getPartner(vmInfo.getOwnerId());
        order.setOwnerId(partner.getId());//分成价钱
        BigDecimal bg = new BigDecimal(sku.getRealPrice());
        int bill = bg.multiply(new BigDecimal(partner.getRatio())).divide(new BigDecimal(100), 0, RoundingMode.HALF_UP).intValue();
        order.setBill(bill);
        save(order);
        //发送协议
        sendOrderMsg(order);
        log.info("发送检查订单支付协议成功");
        return order;
    }


    /**
     * 发送协议
     *
     * @param order
     */
    public void sendOrderMsg(OrderEntity order) {
        //创建协议类
        OrderCheck orderCheck = new OrderCheck();
        orderCheck.setOrderNo(order.getOrderNo());
        orderCheck.setInnerCode(order.getInnerCode());
        try {
            mqttProducer.send("$delayed/300/" + TopicConfig.ORDER_CHECK_TOPIC, 2, orderCheck);
        } catch (JsonProcessingException e) {
            log.error("send to emq error", e);
            e.printStackTrace();
        }
    }

    /**
     * 商品出货
     *
     * @param orderNo
     * @param skuId
     * @param innerCode
     */
    // @Transactional
    @Override
    public Boolean vendingOut(String orderNo, Long skuId, String innerCode) {
        //1.创建出货封装的协议类
        VendoutContract contract = new VendoutContract();
        //封装参数信息
        VendoutData data = new VendoutData();
        data.setSkuId(skuId);
        data.setOrderNo(orderNo);
        //封装协议类
        contract.setInnerCode(innerCode);
        contract.setVendoutData(data);
        //2.发送mq消息 售货机出货  "vm/" + innerCode + "/vendout"
        try {
            mqttProducer.send(TopicConfig.VMS_VENDOUT_TOPIC, 2, contract);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}
